package com.lonely.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.Cascader;
import com.lonely.common.core.domain.Select;
import com.lonely.system.domain.entity.SysUser;
import com.lonely.common.enums.UserStatus;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.system.domain.entity.SysFactory;
import com.lonely.system.domain.entity.SysProductionLine;
import com.lonely.system.domain.dto.productionline.SysProductionLineStatQueryDto;
import com.lonely.system.domain.dto.productionline.SysProductionLineSubmitDto;
import com.lonely.system.domain.vo.system.productionline.SysProductionLineStatsVo;
import com.lonely.system.enums.SysProductionLineEnum;
import com.lonely.system.mapper.SysProductionLineMapper;
import com.lonely.system.service.ISysFactoryService;
import com.lonely.system.service.ISysProductionLineService;
import com.lonely.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 黄志标
 * @date: 2025/5/27 11:36
 * @description: 产线接口实现
 */
@Service
public class SysProductionLineServiceImpl extends ServiceImpl<SysProductionLineMapper, SysProductionLine> implements ISysProductionLineService {

    @Autowired
    private ISysFactoryService sysFactoryService;

    @Autowired
    private ISysUserService sysUserService;

    /**
     * 创建产线
     *
     * @param submitDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(SysProductionLineSubmitDto submitDto) {
        Assert.isNull(submitDto.getId(), "参数错误(id)");

        // 判断工厂名称是否已存在
        checkProductionLine(submitDto);

        // 入库
        SysProductionLine sysProductionLine = new SysProductionLine();
        BeanUtils.copyProperties(submitDto, sysProductionLine);
        sysProductionLine.setStatus(SysProductionLineEnum.ProductionLineStatus.ENABLE.status);
        sysProductionLine.setCreateBy(SecurityUtils.getUserId());
        sysProductionLine.setUpdateBy(SecurityUtils.getUserId());
        super.save(sysProductionLine);
    }

    /**
     * 编辑产线
     *
     * @param submitDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysProductionLineSubmitDto submitDto) {
        Assert.notNull(submitDto.getId(), "参数错误(id)");

        // 判断工厂名称是否已存在
        checkProductionLine(submitDto);

        SysProductionLine oldProductionLine = super.getById(submitDto.getId());
        BeanUtils.copyProperties(submitDto, oldProductionLine);
        oldProductionLine.setCreateBy(SecurityUtils.getUserId());
        oldProductionLine.setUpdateBy(SecurityUtils.getUserId());

        super.updateById(oldProductionLine);
    }

    /**
     * 产线统计
     *
     * @param queryDto
     * @return
     */
    @Override
    public SysProductionLineStatsVo stat(SysProductionLineStatQueryDto queryDto) {

        // 获取产线列表
        List<SysProductionLine> pls = Optional.ofNullable(super.list(new LambdaQueryWrapper<SysProductionLine>()
                        .eq(SysProductionLine::getFactoryId, queryDto.getFactoryId())
                        .like(StrUtil.isNotBlank(queryDto.getName()), SysProductionLine::getName, queryDto.getName())
                        .eq(queryDto.getStatus() != null, SysProductionLine::getStatus, queryDto.getStatus()))
                )
                .orElse(new ArrayList<>());
        if (CollUtil.isEmpty(pls)) {
            return new SysProductionLineStatsVo();
        }

        // 获取该工厂的用户信息
        List<SysUser> users = this.sysUserService.list(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getFactoryId, queryDto.getFactoryId())
                .eq(SysUser::getStatus, UserStatus.ENABLED.getCode()));

        //根据产线id进行分组
        Map<Long, Long> plUserNumMap = new HashMap<>();
        if (CollUtil.isNotEmpty(users)) {
            plUserNumMap.putAll(users.stream().collect(Collectors.groupingBy(SysUser::getProductionLineId, Collectors.counting())));
        }

        // 查询工厂信息
        SysFactory sysFactory = this.sysFactoryService.getById(queryDto.getFactoryId());

        // 根据类型进行分组
        List<SysProductionLineStatsVo.SysProductionLineStatVo> plStats = pls.stream()
                .map(pl -> {
                    SysProductionLineStatsVo.SysProductionLineStatVo productionLineStatVo = new SysProductionLineStatsVo.SysProductionLineStatVo();
                    productionLineStatVo.setId(pl.getId());
                    productionLineStatVo.setName(pl.getName());
                    productionLineStatVo.setType(pl.getType());
                    productionLineStatVo.setEmployeeNum(Convert.toInt(MapUtil.getLong(plUserNumMap, pl.getId(), 0L)));
                    productionLineStatVo.setFactoryId(pl.getFactoryId());
                    return productionLineStatVo;
                }).collect(Collectors.toList());

        List<SysProductionLineStatsVo.SysProductionLineStatVo> functionPlStats = plStats.stream()
                .filter(factory -> Objects.equals(factory.getType(), SysProductionLineEnum.ProductionLineType.FUNCTION_GROUP.type)).collect(Collectors.toList());
        List<SysProductionLineStatsVo.SysProductionLineStatVo> tailorPlStats = plStats.stream()
                .filter(factory -> Objects.equals(factory.getType(), SysProductionLineEnum.ProductionLineType.TAILOR_GROUP.type)).collect(Collectors.toList());
        List<SysProductionLineStatsVo.SysProductionLineStatVo> sewingPlStats = plStats.stream()
                .filter(factory -> Objects.equals(factory.getType(), SysProductionLineEnum.ProductionLineType.SEWING_GROUP.type)).collect(Collectors.toList());
        List<SysProductionLineStatsVo.SysProductionLineStatVo> postWholePlStats = plStats.stream()
                .filter(factory -> Objects.equals(factory.getType(), SysProductionLineEnum.ProductionLineType.POST_WHOLE_GROUP.type)).collect(Collectors.toList());

        SysProductionLineStatsVo plStatVo = new SysProductionLineStatsVo();
        plStatVo.setTotalGroupNum(plStats.size());
        plStatVo.setTotalFunctionPlGroupNum(functionPlStats.size());
        plStatVo.setTotalFunctionPlEmployeeNum(functionPlStats.stream().mapToInt(SysProductionLineStatsVo.SysProductionLineStatVo::getEmployeeNum).sum());
        plStatVo.setTotalTailorPlGroupNum(tailorPlStats.size());
        plStatVo.setTotalTailorPlEmployeeNum(tailorPlStats.stream().mapToInt(SysProductionLineStatsVo.SysProductionLineStatVo::getEmployeeNum).sum());
        plStatVo.setTotalSewingPlGroupNum(sewingPlStats.size());
        plStatVo.setTotalSewingPlEmployeeNum(sewingPlStats.stream().mapToInt(SysProductionLineStatsVo.SysProductionLineStatVo::getEmployeeNum).sum());
        plStatVo.setTotalPostWholePlGroupNum(postWholePlStats.size());
        plStatVo.setTotalPostWholePlEmployeeNum(postWholePlStats.stream().mapToInt(SysProductionLineStatsVo.SysProductionLineStatVo::getEmployeeNum).sum());
        plStatVo.setFactoryName(sysFactory.getName());
        plStatVo.setFunctionPl(functionPlStats);
        plStatVo.setTailorPl(tailorPlStats);
        plStatVo.setSewingPl(sewingPlStats);
        plStatVo.setPostWholePl(postWholePlStats);
        return plStatVo;
    }

    /**
     * 产线下拉框列表
     *
     * @return
     */
    @Override
    public List<Select> getSelect(Long factoryId) {
        // 获取工厂信息
        SysFactory factory = this.sysFactoryService.getById(factoryId);
        Assert.notNull(factory, "工厂不存在");

        return Optional.ofNullable(super.list(new LambdaQueryWrapper<SysProductionLine>().eq(SysProductionLine::getFactoryId, factoryId)))
                .orElse(new ArrayList<>())
                .stream().map(x -> new Select().setLabel(String.format("%s-%s", factory.getName(), x.getName())).setValue(Convert.toStr(x.getId())))
                .collect(Collectors.toList());
    }

    /**
     * 产线对应的生产工种下拉框列表
     *
     * @param productionLineId
     * @return
     */
    @Override
    public List<Select> getWorkTypeSelect(Long productionLineId) {
        SysProductionLine productionLine = super.getById(productionLineId);
        Assert.notNull(productionLine, "该产线不存在");
        return Optional.ofNullable(SysProductionLineEnum.WorkTypeEnum.getWorkTypeEnumByPlType(productionLine.getType())).orElse(new ArrayList<>())
                .stream().map(x -> new Select().setLabel(x.workTypeName).setValue(Convert.toStr(x.workType))).collect(Collectors.toList());
    }

    /**
     * 暂停分单
     *
     * @param plId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void suspendSplitOrders(Long plId) {
        super.update(new LambdaUpdateWrapper<SysProductionLine>()
                .eq(SysProductionLine::getId, plId)
                .set(SysProductionLine::getStatus, SysProductionLineEnum.ProductionLineStatus.SUSPEND_SPLIT_ORDERS.status)
                .set(SysProductionLine::getUpdateBy, SecurityUtils.getUserId())
        );
    }

    /**
     * 停用产线/分组
     *
     * @param plId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void stopUsing(Long plId) {
        super.update(new LambdaUpdateWrapper<SysProductionLine>()
                .eq(SysProductionLine::getId, plId)
                .set(SysProductionLine::getStatus, SysProductionLineEnum.ProductionLineStatus.DISABLE.status)
                .set(SysProductionLine::getUpdateBy, SecurityUtils.getUserId())
        );
    }

    /**
     * 获取产线级联选择器数据
     *
     * @return
     */
    @Override
    public List<Cascader> getProductionLineCascader() {
        // 工厂列表
        List<SysFactory> factories = this.sysFactoryService.list();
        List<Long> factoryIds = factories.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList());

        Map<Long, List<SysProductionLine>> factoryPlMap = Optional.ofNullable(super.list(new LambdaQueryWrapper<SysProductionLine>()
                        .in(SysProductionLine::getFactoryId, factoryIds)))
                .orElse(new ArrayList<>()).stream().collect(Collectors.groupingBy(SysProductionLine::getFactoryId));

        List<Cascader> cascaders = new ArrayList<>();

        for (SysFactory factory : factories) {
            Cascader cascader = new Cascader();
            cascader.setLabel(factory.getName());
            cascader.setValue(String.format("factory_%s",factory.getId()));

            List<Cascader> currentPlCascaders = new ArrayList<>();
            if (factoryPlMap.containsKey(factory.getId())) {
                for (SysProductionLine sysProductionLine : factoryPlMap.get(factory.getId())) {
                    Cascader plCascader = new Cascader();
                    plCascader.setLabel(sysProductionLine.getName());
                    plCascader.setValue(sysProductionLine.getId());
                    plCascader.setChildren(null);
                    currentPlCascaders.add(plCascader);
                }
            }
            cascader.setChildren(currentPlCascaders);
            cascaders.add(cascader);
        }
        return cascaders;
    }


    /**
     * 校验产线信息
     *
     * @param submitDto
     */
    private void checkProductionLine(SysProductionLineSubmitDto submitDto) {

        //1. 校验产线是否已存在
        int count = super.count(new LambdaQueryWrapper<SysProductionLine>().eq(SysProductionLine::getName, submitDto.getName())
                .eq(SysProductionLine::getFactoryId, submitDto.getFactoryId())
                .eq(SysProductionLine::getType, submitDto.getType())
                .ne(submitDto.getId() != null, SysProductionLine::getId, submitDto.getId()));
        Assert.isTrue(count == 0, "该产线已存在");

        //2. 检验产线id对应的数据是否存在
        if (submitDto.getId() != null) {
            SysProductionLine oldPl = super.getById(submitDto.getId());
            Assert.notNull(oldPl, "该产线不存在");
        }

        //3. 校验工厂id是否存在
        SysFactory factory = this.sysFactoryService.getById(submitDto.getFactoryId());
        Assert.notNull(factory, "工厂不存在");
    }
}
